home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Delphi Magazine Collection 2001
/
Delphi Magazine Collection 20001 (2001).iso
/
DISKS
/
ISSUE18
/
SURVIVE
/
LOGIN.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-12-06
|
14KB
|
429 lines
unit Login;
interface
uses
Classes, Forms, SysUtils, DB, DBTables;
const
cNoUserID = -1; { Token for no user connected }
cNoAppID = -1; { Token for no application defined }
DefNumAttempts = 3; { Default number of login retry attempts }
type
TLoginEvent = procedure(Sender: TObject; UserName: string; Password: string) of object;
TLoggingInEvent = procedure(Sender: TObject; UserName: string; Password: string; var Cancel: Boolean) of object;
TLoggingOutEvent = procedure(Sender: TObject; var Cancel: Boolean) of object;
TPasswordExpiredEvent = procedure (Sender: TObject; var Cancel: Boolean) of object;
TDBList = class(TList)
public
function Add(Item: TDatabase): Integer;
end;
TLoginManager = class(TComponent)
protected
FApplicationDBs: TDBList; { List of ancillary TDatabase components }
FApplicationID: LongInt; { Identifier for the application }
FCallersDatabaseName: string; { Application's dbname for main db }
FCallersServerName: string; { Application's server name for main db }
FDatabaseName: string; { Db name for main db for this connection }
FDateLastLogin: TDateTime; { Date/time of the last login for this user }
FPasswordExpired: Boolean; { True if user's password has expired on this login }
FMainDB: TDatabase; { Pointer to the application's TDatabase component }
FNumAttemptsAllowed: Integer; { Number of login retries allowed }
FNumFailedAttempts: Integer; { Number of failed login attempts so far }
FPassword: string; { User's password }
FServerName: string; { Server name for main db for this connection }
FUserFirstName: string; { Proper first name for user }
FUserFullName: string; { Proper full name for user }
FUserLastName: string; { Proper last name for user }
FUserID: LongInt; { System ID for user }
FUsername: string; { Login username for user }
FOnLogin: TLoginEvent; { Event-handler }
FOnLoggingIn: TLoggingInEvent; { Event-handler }
FOnLogout: TNotifyEvent; { Event-handler }
FOnLoggingOut: TLoggingOutEvent; { Event-handler }
FOnBadLogin: TNotifyEvent; { Event-handler }
FOnPasswordExpired: TPasswordExpiredEvent;
procedure Connect;
procedure ConnectDB(DB: TDatabase; Username, Password: string);
procedure Disconnect;
procedure DisconnectDB(DB: TDatabase);
function GetDBParamValue(ParamName: string): string;
procedure SetDatabaseName(Value: string);
procedure SetDBParamValue(ParamName, Value: string);
procedure SetMainDB(Value: TDatabase);
procedure SetServerName(Value: string);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Login(UserName, Password, Server, Database: string);
procedure Logout;
procedure ChangePassword(OldPassword, NewPassword: string);
property ApplicationDBs: TDBList
read FApplicationDBs write FApplicationDBs;
property ApplicationID: LongInt
read FApplicationID write FApplicationID;
property DatabaseName: string
read FDatabaseName;
property MainDB: TDatabase
read FMainDB write SetMainDB;
property NumAttemptsAllowed: Integer
read FNumAttemptsAllowed write FNumAttemptsAllowed default defNumAttempts;
property Password: string
read FPassword;
property ServerName: string
read FServerName;
property UserFirstName: string
read FUserFirstName;
property UserFullName: string
read FUserFullName;
property UserLastName: string
read FUserLastName;
property UserID: LongInt
read FUserID;
property Username: string
read FUsername;
property OnLogin: TLoginEvent
read FOnLogin write FOnLogin;
property OnLoggingIn: TLoggingInEvent
read FOnLoggingIn write FOnLoggingIn;
property OnLogout: TNotifyEvent
read FOnLogout write FOnLogout;
property OnLoggingOut: TLoggingOutEvent
read FOnLoggingOut write FOnLoggingOut;
property OnBadLogin: TNotifyEvent
read FOnBadLogin write FOnBadLogin;
property OnPasswordExpired: TPasswordExpiredEvent
read FOnPasswordExpired write FOnPasswordExpired;
end;
var
LoginManager: TLoginManager;
implementation
uses
Controls, Dialogs, DMLogin, PassInt;
{ TDBList }
function TDBList.Add(Item: TDatabase): Integer;
begin
Result := inherited Add(Item);
end;
{ TLoginManager }
constructor TLoginManager.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
{ Establish connection to the data module code }
LoginDM := TLoginDM.Create(Self);
FApplicationID := cNoAppID;
FUserID := cNoUserID;
FUserFullName := '';
FUserFirstName := '';
FUserLastName := '';
FNumAttemptsAllowed := DefNumAttempts;
FApplicationDBs := TDBList.Create;
end;
destructor TLoginManager.Destroy;
begin
FApplicationDBs.Free;
end;
procedure TLoginManager.Connect;
var
I: Integer;
begin
ConnectDB(FMainDB, FUsername, FPassword);
for I := 0 to FApplicationDBs.Count - 1 do
ConnectDB(FApplicationDBs.Items[I], FUsername, FPassword);
end;
procedure TLoginManager.ConnectDB(DB: TDatabase; Username, Password: String);
begin
if DB <> nil then
with DB do
begin
Connected := False;
LoginPrompt := False;
Params.Values['USER NAME'] := Username;
Params.Values['PASSWORD'] := Password;
KeepConnection := True;
Connected := True;
end;
end;
procedure TLoginManager.Disconnect;
var
I: Integer;
begin
DisconnectDB(FMainDB);
for I := 0 to FApplicationDBs.Count - 1 do
DisconnectDB(FApplicationDBs.Items[I]);
end;
procedure TLoginManager.DisconnectDB(DB: TDatabase);
begin
if DB <> nil then
with DB do
begin
KeepConnection := False;
Connected := False;
end;
end;
procedure TLoginManager.Login(UserName, Password, Server, Database: string);
var
Cancel: Boolean;
begin
Logout;
FUsername := Username;
FPassword := Uppercase(Password);
try
{ Any exception occurring within this block is considered a failed login attempt }
{ Deal with possible server/database name overrides }
SetServerName(Server);
SetDatabaseName(Database);
{ Connect to physical database }
Connect;
FUserID := cNoUserID;
LoginDM.GetUserValues(FUserID, FUserFirstName, FUserLastName,
FDateLastLogin, FPasswordExpired);
FUserFullName := FUserFirstName + ' ' + FUserLastName;
{ Determine if user's password has expired... }
if FPasswordExpired then
begin
Cancel := True;
if Assigned(FOnPasswordExpired) then
FOnPasswordExpired(Self, Cancel);
if Cancel then
raise Exception.Create('Unable to login--user''s password has expired');
end;
if Assigned(FOnLoggingIn) then
begin
FOnLoggingIn(Self, UserName, Password, Cancel);
begin
Disconnect;
Exit;
end;
end;
LoginDM.PostAuditTrail(evtLoginSuccessful, '');
LoginDM.PostUserLoginDate;
FNumFailedAttempts := 0;
except
on E: Exception do
begin { Failed login attempt }
Application.HandleException(Self);
Disconnect;
if Assigned(FOnBadLogin) then
FOnBadLogin(Self);
{ Post bad login event }
try
LoginDM.PostAuditTrail(evtLoginFail, 'Username: ' + FUsername);
except
end;
{ Count the number of failed attempts and shut down if the fail limit has been reached }
Inc(FNumFailedAttempts);
if FNumFailedAttempts >= NumAttemptsAllowed then
begin
MessageDlg(IntToStr(FNumFailedAttempts) +
' login attempts have failed. ' +
'Shutting down the application.',
mtError, [mbOk], 0);
Application.Terminate;
end;
FUserID := cNoUserID;
FUsername := '';
FPassword := '';
Exit;
end;
end;
if Assigned(FOnLogin) then
FOnLogin(Self, UserName, Password);
end;
procedure TLoginManager.Logout;
var
Cancel: Boolean;
begin
if FUserID <> cNoUserID then
begin
if Assigned(FOnLoggingOut) then
begin
Cancel := False;
FOnLoggingOut(Self, Cancel);
if Cancel then Exit;
end;
Disconnect;
if Assigned(FOnLogout) then FOnLogout(Self);
LoginDM.PostAuditTrail(evtLogout, '');
FUserID := cNoUserID;
end;
end;
procedure TLoginManager.SetMainDB(Value: TDatabase);
var
I: Integer;
begin
if Value <> FMainDB then
begin
FMainDB := Value;
LoginDM.dbInternal.AliasName := FMainDB.AliasName;
{ Initialize the dataset components in the data module }
for I := 0 to LoginDM.ComponentCount - 1 do
if LoginDM.Components[I] is TDBDataSet then
with TDBDataSet(LoginDM.Components[I]) do
begin
if DatabaseName = '' then
begin
Active := False;
DatabaseName := FMainDB.DatabaseName;
end;
end;
{ ServerName and/or DatabaseName overrides could have been registered already.
If not, then we must make sure the ServerName and DatabaseName
properties return the values given in the application's TDatabase component,
or in the alias definition. }
FCallersServerName := GetDBParamValue('SERVER NAME');
if FServerName <> '' then SetDBParamValue('SERVER NAME', FServerName)
else FServerName := FCallersServerName;
FCallersDatabaseName := GetDBParamValue('DATABASE NAME');
if FDatabaseName <> '' then SetDBParamValue('DATABASE NAME', FDatabaseName)
else FDatabaseName := FCallersDatabaseName;
end;
end;
procedure TLoginManager.ChangePassword(OldPassword, NewPassword: string);
var
Status: Word;
StatusText: PChar;
begin
if Uppercase(OldPassword) <> FPassword then
raise Exception.Create('Unable to change password--current password incorrect.');
StatusText := StrAlloc(255);
try
if PassInt.ChangePassword(
PChar(FMainDB.AliasName),
PChar(FServerName),
PChar(FDatabaseName),
PChar(FUsername),
PChar(OldPassword),
PChar(NewPassword),
StatusText) <> 0 then
raise Exception.Create(StrPas(StatusText));
{ Set the new password }
FPassword := Uppercase(NewPassword);
{ Reconnect database(s) with new password }
Connect;
{ Post a "change password" in the audit trail }
LoginDM.PostAuditTrail(evtChangePassword, '');
finally
StrDispose(StatusText);
end;
end;
function TLoginManager.GetDBParamValue(ParamName: string): string;
{ Returns the value for the given database parameter. }
var
DBParams: TStringList;
begin
{ First, check for specific values in the application's main
TDatabase component. }
Result := FMainDB.Params.Values[ParamName];
{ Failing that, get the value from the alias definition. }
if Result = '' then
begin
DBParams := TStringList.Create;
try
Session.GetAliasParams(FMainDB.AliasName, DBParams);
Result := DBParams.Values[ParamName];
finally
DBParams.Free;
end;
end;
end;
procedure TLoginManager.SetDBParamValue(ParamName, Value: string);
begin
FMainDB.Params.Values[ParamName] := Value;
LoginDM.dbInternal.Params.Values[ParamName] := Value;
end;
procedure TLoginManager.SetDatabaseName(Value: String);
{ When used to register the TLoginManager class, this overrides the "Database Name"
alias property in the MainDB component. It is illegal to set this value once
the MainDB database component is connected.
This code must allow for the DatabaseName property to be set either before or after
the user has registered the MainDB database component. }
begin
FDatabaseName := ANSIUppercase(Value);
{ If MainDB has already been registered... }
if FMainDB <> nil then
begin
if FMainDB.Connected or LoginDM.dbInternal.Connected then
raise Exception.Create('Cannot set TLoginManager.DatabaseName once database is connected');
if FDatabaseName = '' then
FDatabaseName := FCallersDatabaseName;
SetDBParamValue('DATABASE NAME', FDatabaseName);
end;
end;
procedure TLoginManager.SetServerName(Value: string);
{ When used to register the TLoginManager class, this overrides the "Server Name"
alias property in the MainDB component. It is illegal to set this value once
the MainDB database component is connected.
This code must allow for the ServerName property to be set either before or after
the user has registered the MainDB database component. }
begin
FServerName := ANSIUppercase(Value);
{ If MainDB has already been registered... }
if FMainDB <> nil then
begin
if FMainDB.Connected or LoginDM.dbInternal.Connected then
raise Exception.Create('Cannot set TLoginManager.ServerName once database is connected');
if FServerName = '' then
FServerName := FCallersServerName;
SetDBParamValue('SERVER NAME', FServerName);
end;
end;
initialization
LoginManager := nil;
LoginManager := TLoginManager.Create(Application);
end.